package com.leyou.item.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.constants.MQConstants;
import com.leyou.common.exception.pojo.ExceptionEnum;
import com.leyou.common.exception.pojo.LyException;
import com.leyou.common.pojo.PageResult;
import com.leyou.common.utils.BeanHelper;
import com.leyou.item.dto.SputDTO;
import com.leyou.item.mapper.SkuMapper;
import com.leyou.item.mapper.SpuDetailMapper;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.pojo.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 商品业务
 *  ServiceImpl<SkuMapper,Sku>：
 *     泛型一：操作Mapper接口
 *     泛型二：操作的Pojo类型
 */
@Service
@Transactional
public class GoodsService extends ServiceImpl<SkuMapper,Sku>{
    @Autowired
    private SpuMapper spuMapper;
    @Autowired
    private SpuDetailMapper spuDetailMapper;
    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private AmqpTemplate amqpTemplate;

    public PageResult<SputDTO> spuPageQuery(Integer page, Integer rows, String key, Boolean saleable) {
        //1.封装条件（查询条件、分页条件）
        QueryWrapper<Spu> queryWrapper = Wrappers.query();

        //1.1 查询条件
        //现在的SQL: name like '%华为%' or sub_title like '%华为%' and saleable=1
        //预期的SQL: (name like '%华为%' or sub_title like '%华为%') and saleable=1

        //搜索条件
        if(StringUtils.isNotEmpty(key)){

            //and: 把查询条件聚合在一起
            queryWrapper.and(q->q.like("name",key)
                    .or()
                    .like("sub_title",key));

        }
        //上下架
        if(saleable!=null){
            queryWrapper.eq("saleable",saleable);
        }

        //1.2 分页条件
        IPage<Spu> iPage = new Page(page,rows);

        //2.执行查询，获取结果
        iPage = spuMapper.selectPage(iPage,queryWrapper);

        //3.处理结果
        //3.1 取出Spu列表
        List<Spu> spuList = iPage.getRecords();
        //3.2 把Spu列表转换为SpuDTO列表
        List<SputDTO> sputDTOList = BeanHelper.copyWithCollection(spuList, SputDTO.class);
        //3.3 往SpuDTO列表补充分类名称和品牌名称
        getCategoryNameAndBrandName(sputDTOList);
        //3.4 封装成PageResult
        PageResult<SputDTO> pageResult = new PageResult<>(iPage.getTotal(),iPage.getPages(),sputDTOList);

        //4.返回结果
        return pageResult;
    }

    /**
     * 填充SpuDTO列表的中categoryName和brandName属性
     * @param sputDTOList
     */
    private void getCategoryNameAndBrandName(List<SputDTO> sputDTOList) {
        //遍历列表
        sputDTOList.forEach(sputDTO -> {
            //1.查询品牌并设置品牌名称
            Brand brand = brandService.findBrandById(sputDTO.getBrandId());
            sputDTO.setBrandName(brand.getName());

            //2.查询分类并设置分类名称
            //Arrays.asList(): 把数组（可变长参数）转换为List集合
            List<Long> categoryIds = Arrays.asList(sputDTO.getCid1(),sputDTO.getCid2(),sputDTO.getCid3());
            List<Category> categoryList = categoryService.findCategoriesByIds(categoryIds);
            //格式：手机通讯/手机/手机
            /**
             * stream流式编程/链式编程
             *   作用/应用场景： 方便操作集合
             *   常用方法：
             *        stream(): 获取一个集合的流
             *        map(): 对集合元素进行映射。通俗地说，对集合每个元素进行怎样的操作？ 例如获取List<Category>的Category的name属性
             *        collect(): 对map方法结果进行归总。
             *             例如，
             *                把刚才map方法取出每个name属性，存入一个新的List集合并返回
             *                把刚才map方法取出每个name属性，使用指定分隔符拼接一个新的字符串并返回
             */
            //map(category -> category.getName()): Lambada一种写法
            //map(Category::getName)： Lambada另一种写法（简化版本）

            String categoryName = categoryList
                                    .stream()
                                    .map(Category::getName)
                                    .collect(Collectors.joining("/"));
            sputDTO.setCategoryName(categoryName);

        });
    }

    public void saveGoods(SputDTO sputDTO) {
        try {
            //1.保存Spu表
            //1.1 把SpuDTO转换为Spu对象
            Spu spu = BeanHelper.copyProperties(sputDTO, Spu.class);
            //1.2 默认下架状态
            spu.setSaleable(false);
            //1.3 保存
            spuMapper.insert(spu);

            //2.保存SpuDetail表
            SpuDetail spuDetail = sputDTO.getSpuDetail();
            //2.1 设置SpuId
            spuDetail.setSpuId(spu.getId());
            spuDetailMapper.insert(spuDetail);

            //3.保存Sku表
            List<Sku> skus = sputDTO.getSkus();
            //给所有Sku对象设置SpuId
            skus.forEach(sku -> {
                sku.setSpuId(spu.getId());
                //skuMapper.insert(sku);
            });
            //批量增加: saveBatch该方法来自于ServiceImpl类
            this.saveBatch(skus);
        } catch (Exception e) {
            e.printStackTrace();
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
    }

    public void updateSaleable(Long id, Boolean saleable) {
        try {
            Spu spu = new Spu();
            spu.setId(id);
            spu.setSaleable(saleable);

            spuMapper.updateById(spu); // 注意： updateById该方法自动判断如果存在NULL属性，则不更新该属性。


            //发送MQ的消息
            String routingKey = saleable? MQConstants.RoutingKey.ITEM_UP_KEY:MQConstants.RoutingKey.ITEM_DOWN_KEY;
            amqpTemplate.convertAndSend(MQConstants.Exchange.ITEM_EXCHANGE_NAME,routingKey,id);
        } catch (Exception e) {
            e.printStackTrace();
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }
    }

    public List<Sku> findSkusBySpuId(Long id) {
        //1.封装条件
        Sku sku = new Sku();
        sku.setSpuId(id);

        QueryWrapper<Sku> queryWrapper = Wrappers.query(sku);

        //2.执行查询
        List<Sku> skus = skuMapper.selectList(queryWrapper);

        //3.处理结果
        if(CollectionUtils.isEmpty(skus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }

        //4.返回数据
        return skus;
    }

    public SpuDetail findSpuDetailBySpuId(Long id) {
        SpuDetail spuDetail = spuDetailMapper.selectById(id);
        if(spuDetail==null){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return spuDetail;
    }

    public SputDTO findSpuById(Long id) {
        try {
            //1.根据spuId查询Spu对象
            Spu spu = spuMapper.selectById(id);
            //2.把Spu数据拷贝到SpuDTO
            SputDTO sputDTO = BeanHelper.copyProperties(spu, SputDTO.class);

            //2.设置分类名称
            List<Category> categoryList = categoryService.findCategoriesByIds(Arrays.asList(sputDTO.getCid1(),sputDTO.getCid2(),sputDTO.getCid3()));
            String categoryName = categoryList.stream().map(Category::getName).collect(Collectors.joining("/"));
            sputDTO.setCategoryName(categoryName);

            //3.设置品牌名称
            Brand brand = brandService.findBrandById(sputDTO.getBrandId());
            sputDTO.setBrandName(brand.getName());

            //4.设置SpuDetail
            SpuDetail detail = spuDetailMapper.selectById(id);
            sputDTO.setSpuDetail(detail);

            //5.设置Sku列表，并且库存>0&&enable==1
            List<Sku> skus = this.usableSku(id);
            sputDTO.setSkus(skus);

            return sputDTO;
        } catch (Exception e) {
            e.printStackTrace();
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
    }

    public List<Sku> findSkusBySkuIds(List<Long> ids) {
        List<Sku> skus = skuMapper.selectBatchIds(ids);
        if(CollectionUtils.isEmpty(skus)){
            throw new LyException(ExceptionEnum.GOODS_NOT_FOUND);
        }
        return skus;
    }

    public  void minusStock(Map<Long, Integer> paramMap) {

        //遍历所有商品
        paramMap.entrySet().forEach(entry->{
            Long skuId = entry.getKey();
            Integer num = entry.getValue();

            //查询商品（包括原库存量)
            Sku sku = skuMapper.selectById(skuId);

            if(sku.getStock()>=num){//库存量足够才扣减库存
                sku.setStock(sku.getStock()-num);
                //更新库存
                skuMapper.updateById(sku);
            }

        });
    }
    /*
     * 加库存
     * */
    public void plusStock(Map<Long, Integer> paramPlusMap) {
        //遍历所有商品
        paramPlusMap.entrySet().forEach(entry->{
            Long skuId = entry.getKey();
            Integer num = entry.getValue();

            //创建sku对象
            Sku entity = new Sku();
            entity.setId(skuId);
            //查询商品（包括原库存量)
            Sku sku = skuMapper.selectById(skuId);
            //添加库存
            sku.setStock(sku.getStock()+num);
            //更新库存
            skuMapper.updateById(entity);
        });

    }

    //根据id查询库存>0 &&enable ==1的sku
    public List<Sku> usableSku(Long id){
        //构建查询器
        QueryWrapper<Sku> query = Wrappers.query();
        //and: 把查询条件聚合在一起
        query.and(q->q.eq("spu_id",id).
                gt("stock",0)
               .eq("enable",1));

        //执行查询
        List<Sku> skuList = skuMapper.selectList(query);
        return skuList;
    }
}
